#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <sys/poll.h>

#define maxNum 10;

//任务类
typedef struct JOB
{
    void*(*callback_function)(void* arg); //任务函数
    void* arg;
    struct JOB* pNext;

}job;
//
// typedef struct JOBList
// {
//     job j;
//     struct JOBList* pNext;
// }jobList;


//线程池类
typedef struct pthreadPool
{
    pthread_t* pthreads; //数组方式存储所有线程ID
    job* head; //任务池头节点
    job* tail; //任务池尾节点

    int  nums; //当前线程数
    int quque_max_num;  //当前最大线程数
    //线程同步
    pthread_mutex_t mutex; //互斥量
    pthread_cond_t queue_empty; //当前池空了
    pthread_cond_t queue_not_empty; //不空
    pthread_cond_t queue_not_full; //不满

    int queue_job_nums; //当前任务数

    int queue_close;//是否关闭任务池
    int pool_close; //是否关闭线程池
} pthread_pool;

//任务函数
void* work(void* arg);

//线程函数
void* threadFunction(void* arg);

//创建线程池对象并初始化
pthread_pool* pthreadPoolInit(int pthread_num, int queue_max_num);

//添加任务到线程池中
int addJobToPool(pthread_pool* pool, void*(*callback_function)(void* arg),void* arg);

//销毁线程池
int destroyPool(pthread_pool* pool);

int main()
{

    pthread_pool* pool = pthreadPoolInit(5,20);
    addJobToPool(pool,work,"第1个任务");
    addJobToPool(pool,work,"第2个任务");
    addJobToPool(pool,work,"第3个任务");
    addJobToPool(pool,work,"第4个任务");
    addJobToPool(pool,work,"第5个任务");
    addJobToPool(pool,work,"第6个任务");
    addJobToPool(pool,work,"第7个任务");
    addJobToPool(pool,work,"第8个任务");
    addJobToPool(pool,work,"第9个任务");
    addJobToPool(pool,work,"第10个任务");
    addJobToPool(pool,work,"第11个任务");
    addJobToPool(pool,work,"第12个任务");
    addJobToPool(pool,work,"第13个任务");
    addJobToPool(pool,work,"第14个任务");
    addJobToPool(pool,work,"第15个任务");
    addJobToPool(pool,work,"第16个任务");
    addJobToPool(pool,work,"第17个任务");
    addJobToPool(pool,work,"第18个任务");
    addJobToPool(pool,work,"第19个任务");
    addJobToPool(pool,work,"第20个任务");
    sleep(30);
    destroyPool(pool);
    return 0;
}

//任务函数
void* work(void* arg)
{
    char* str = (char*) arg;
    printf("任务函数开始:%s\n",str);
    sleep(10);
    printf("任务函数结束:%s\n",str);
}

//线程函数
void* threadFunction(void* arg)
{
    //拿到线程池
    pthread_pool* pool = (pthread_pool*) arg;
    if (pool==NULL)
    {
        return NULL;
    }

    //获取具体任务
    job* pJob = NULL;

    while (1)
    {
        pthread_mutex_lock(&(pool->mutex));

        //监督线程的工作在这里做了

        //如何队列为空 就阻塞 队列非空 就往下执行
        while (0==pool->queue_job_nums && !pool->queue_close)
        {
            printf("队列为空 阻塞\n");
            pthread_cond_wait(&(pool->queue_not_empty),&(pool->mutex));
        }

        //线程池是否关闭
        if(pool->queue_close)
        {
            printf("线程池关闭了 结束线程\n");
            pthread_mutex_unlock(&(pool->mutex));
            pthread_exit(NULL);
        }

        //当前任务数减1
        pool->queue_job_nums--;

        pJob  =pool->head;

        if (0==pool->queue_job_nums)
        {
            pool->head=pool->tail=NULL;
            printf("销毁线程函数\n");
            pthread_cond_signal(&(pool->queue_empty));
        }else
        {
            pool->head = pJob->pNext;
        }

        //队列不满 添加新任务
        if (pool->queue_job_nums < pool->quque_max_num)
        {
            printf("队列不满 添加新任务\n");
            pthread_cond_broadcast(&(pool->queue_not_full));
        }
        pthread_mutex_unlock(&(pool->mutex));

        //执行线程函数

        (*(pJob->callback_function))(pJob->arg);

        //释放任务对象
        free(pJob);
        pJob=NULL;

    }
}

//创建线程池对象并初始化
pthread_pool* pthreadPoolInit(int pthread_num, int queue_max_num)
{
    //开内存

    pthread_pool* pool = (pthread_pool*)malloc(sizeof(pthread_pool));
    if (NULL==pool)
    {
        printf("pthreadPoolInit种malloc失败");
        return NULL;
    }
    pool->nums = pthread_num;
    pool->quque_max_num = queue_max_num;
    pool->queue_job_nums=0;
    pool->queue_close=pool->pool_close = 0; //并非关闭状态

    pool->pthreads=(pthread_t*)malloc(sizeof(pthread_t) * pthread_num);

    pthread_mutex_init(&(pool->mutex),NULL);
    pthread_cond_init(&(pool->queue_empty),NULL);
    pthread_cond_init(&(pool->queue_not_empty),NULL);
    pthread_cond_init(&(pool->queue_not_full),NULL);

    pool->head=NULL;
    pool->tail=NULL;

    //创建线程 阻塞在这里

    for (int i=0;i<pool->nums;i++)
    {
        pthread_create(&(pool->pthreads[i]),NULL,threadFunction,(void *)pool);
    }

    //返回
    return pool;

}

//添加任务到线程池中
int addJobToPool(pthread_pool* pool, void*(*callback_function)(void* arg),void* arg)
{
    if (NULL==pool || NULL ==callback_function || NULL==arg)
    {
        printf("addJobToPool函数传参有问题\n");
        return -1;
    }

    //阻塞
    pthread_mutex_lock(&(pool->mutex));

    //队列是否已满
    while ( (pool->queue_job_nums >= pool->quque_max_num) && !(pool->queue_close || pool->pool_close))
    {
        printf("队列满了，阻塞\n");
        pthread_cond_wait(&(pool->queue_not_full),&(pool->mutex));
    }
    //关闭
    if (pool->queue_close || pool->pool_close)
    {
        pthread_mutex_unlock(&(pool->mutex));
        return -1;
    }

    //往任务池种添加任务 开内存
    job* pJob  = (job*)malloc(sizeof(job));

    if (NULL==pJob)
    {
        printf("addJobToPool函数传参种malloc job出错\n");
        pthread_mutex_unlock(&(pool->mutex));
        return -1;
    }

    //成员赋值
    pJob->callback_function = callback_function;
    pJob->arg = arg;
    pJob->pNext = NULL;


    //入列 尾插法
    if (NULL==pool->head)
    {
        pool->head=pool->tail = pJob;
        //队列非空
       pthread_cond_broadcast(&(pool->queue_not_empty));
    }else
    {
        pool->tail->pNext = pJob;
        pool->tail = pJob;
    }
    pool->queue_job_nums+=1;
    printf("添加%s\n",arg);


    pthread_mutex_unlock(&(pool->mutex));

}

//销毁线程池
int destroyPool(pthread_pool* pool)
{
    printf("销毁线程池\n");
    if (pool)
    {
        //释放ID内存
        free(pool->pthreads);

        //如果还有任务 释放掉
        job* pJob = pool->head;
        while(pJob)
        {
            pool->head = pJob->pNext;
            free(pJob);
            pJob = pool->head;
        }

        //释放本身内存；
        free(pool);
        return 0;
    }
    return -1;
}